package helpers;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import utilisateurs.modeles.Categorie;
import utilisateurs.modeles.Fonctionnalite;
import utilisateurs.modeles.ImagesGroup;
import utilisateurs.modeles.Film;
import utilisateurs.modeles.Tag;
import java.util.Arrays;
import java.util.Iterator;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import servlets.LoadServlet;

/*
 * Cette classe permet de constituer notre base de donnée grace à l'API AMAZON
 */
public class AmazonHelper {

    private static final String ENDPOINT = "ecs.amazonaws.com";
    private static final String AWS_ACCESS_KEY_ID = "AKIAJQXAKVNJJ3F5X7SA";
    private static final String AWS_SECRET_KEY = "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";
    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    private static final String[] KEYWORDS = {
        "age of empires", "battlefield", "sponge bob", "call of duty",
        "counter strike", "dead or alive", "dirt", "fable",
        "fifa", "god of war", "gran turismo", "grand theft auto",
        "guitar hero", "half life", "halo", "harry potter",
        "killzone", "littlebigplanet", "mario kart", "motogp",
        "mortal kombat", "naruto", "need for speed", "pokemon",
        "portal", "pro evolution soccer", "red dead redemption", "sonic",
        "splinter cell", "street fighter", "super mario", "test drive",
        "top spin", "world of warcraft", "zelda", "tekken",
        "band hero", "dj hero", "sing star", "alice",
        "ar tonelico", "leisure larry suit", "final fantasy", "plants zombies",
        "hunted", "heroes", "red faction", "thor",
        "infamous", "sudoku", "sims", "cars",
        "duke nukem", "virtua tennis", "dungeon siege", "fear"
    };
    private static final String[] NO_WANTED_TAGS = {
        "All Games", "All product", "Categories", "Games",
        "Mac Games", "More Systems", "Nintendo 3DS", "Nintendo DS",
        "PC Games", "PlayStation 2", "PlayStation 3", "Products",
        "Sony PSP", "Video Games", "Wii", "Xbox", "Xbox 360",
        "Nintendo 64", "PlayStation"
    };

    static {
        // obligatoire pour faire un binarySearch
        Arrays.sort(KEYWORDS);
        Arrays.sort(NO_WANTED_TAGS);
    }

    private AmazonHelper() {
    }

    public static void getXML(LoadServlet servlet) {
        File directory = new File(servlet.getServletContext().getRealPath("xml"));

        // création du dossier xml s'il n'existe pas
        if (!directory.exists() || !directory.isDirectory()) {
            directory.mkdir();
        }

        if (directory.exists() && directory.isDirectory()) {
            try {
                // parametre envoyé à Amazon
                Map<String, String> params = new HashMap<String, String>();
                params.put("Service", "AWSECommerceService");
                params.put("Operation", "ItemSearch");
                params.put("SearchIndex", "VideoGames");
                params.put("ResponseGroup", "Images,ItemAttributes,EditorialReview,BrowseNodes");
                params.put("AssociateTag", "worofvidgam-20");
                
                // Classe de l'API Amazon
                SignedRequestsHelper helper = SignedRequestsHelper.getInstance(ENDPOINT, AWS_ACCESS_KEY_ID, AWS_SECRET_KEY);
                DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

                // Pour chaque mot clé, on crée le fichier xml, on récupère le flux de donnée et on écrit dans le fichier xml
                for (String keyword : KEYWORDS) {
                    try {
                        File file = new File(directory, keyword.replaceAll("[\\W]", "") + ".xml");

                        if (file.length() == 0) {
                            file.delete();
                        }

                        if (file.createNewFile()) {
                            params.put("Keywords", keyword);
                            URL url = new URL(helper.sign(params));
                            ReadableByteChannel rbc = Channels.newChannel(url.openStream());
                            FileOutputStream fos = new FileOutputStream(file);
                            fos.getChannel().transferFrom(rbc, 0, 1 << 24);
                            System.out.println("#### " + file.getAbsolutePath() + " ####");
                        }

                        parseXML(builder, file, servlet);
                    } catch (SAXException ex) {
                        Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (ParseException ex) {
                        Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IOException ex) {
                        Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            } catch (ParserConfigurationException ex) {
                Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
            } catch (UnsupportedEncodingException ex) {
                Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NoSuchAlgorithmException ex) {
                Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvalidKeyException ex) {
                Logger.getLogger(AmazonHelper.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private static void parseXML(DocumentBuilder builder, File file, LoadServlet servlet) throws SAXException, IOException, ParseException {
        Document doc = builder.parse(file);
        NodeList items = doc.getElementsByTagName("Item");

        for (int i=0; i<items.getLength(); i++) {
            Element item = (Element) items.item(i);
            NodeList images = item.getElementsByTagName("ImageSet");
            Element listPrice = DocumentHelper.getElement(item, "ListPrice");
            String amount = DocumentHelper.getValue(listPrice, "Amount");
            String platform = DocumentHelper.getValue(item, "Platform");
            String releaseDate = DocumentHelper.getValue(item, "ReleaseDate");
            String publisher = DocumentHelper.getValue(item, "Publisher");
            String ageRating = DocumentHelper.getValue(item, "ESRBAgeRating");
            NodeList descriptions = item.getElementsByTagName("Content");

            if (ageRating == null || publisher == null || releaseDate == null || amount == null
                    || platform == null || images == null || images.getLength() < 2 || descriptions == null) {
                continue;
            }

            String title = DocumentHelper.getValue(item, "Title");
            Categorie category = servlet.getCategoryFacade().getOrCreate(platform);
            Film videoGame = servlet.getVideoGameFacade().create(title, category);

            if (videoGame == null) {
                continue;
            }

            String description = "";

            for (int j=0; j<descriptions.getLength(); j++) {
                description += descriptions.item(j).getTextContent() + "<br />";
            }

            videoGame.setReleaseDate(FORMAT.parse(releaseDate));
            videoGame.setDescription(description);
            videoGame.setPrice(Double.parseDouble(amount) / 100);
            videoGame.setPublisher(publisher);
            videoGame.setAgeRating(servlet.getAgeRatingFacade().getByName(ageRating));

            for (int j=0; j<images.getLength(); j++) {
                Element image = (Element) images.item(j);
                ImagesGroup imagesGroup = DocumentHelper.getImagesGroup(servlet, image);
                
                if (image.getAttribute("Category").equals("primary")) {
                    videoGame.setImage(imagesGroup);
                } else {
                    videoGame.getImages().add(imagesGroup);
                }
            }

            if (videoGame.getImage() == null) {
                Iterator<ImagesGroup> iterator = videoGame.getImages().iterator();
                videoGame.setImage(iterator.next());
                iterator.remove();
            }

            NodeList nodes = item.getElementsByTagName("BrowseNode");

            for (int j=0; j<nodes.getLength(); j++) {
                Element node = (Element) nodes.item(j);
                String name = DocumentHelper.getValue(node, "Name");

                if (name != null) {
                    String[] splits = name.split(" - ");

                    for (String split : splits) {
                        if (Arrays.binarySearch(NO_WANTED_TAGS, split) < 0) {
                            Tag tag = servlet.getTagFacade().getOrCreate(split);

                            if (!videoGame.getTags().contains(tag)) {
                                videoGame.getTags().add(tag);
                            }
                        }
                    }
                }
            }

            NodeList features = item.getElementsByTagName("Feature");

            for (int j=0; j<features.getLength(); j++) {
                Element feature = (Element) features.item(j);
                videoGame.getFonctionnalites().add(new Fonctionnalite(feature.getTextContent()));
            }

            servlet.getVideoGameFacade().edit(videoGame);
            System.out.println("#### " + file.getName() + " #### " + title + " #### " + platform + " ####");
        }
    }
}